#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cherrypy
import datetime

from farado.logger import logger
from farado.ui.renderer import view_renderer
from farado.helpers.cookie_helper import current_session_id
from farado.helpers.user_statistics_helper import UserStatisticsHelper
from farado.general_manager_holder import project_manager
from farado.items.user import User
from farado.items.user_role import UserRole
from farado.items.message import Message
from farado.ui.operation_result import OperationResult
from farado.ui.base_view import BaseView, UiUserRestrictions
from farado.ui.base_view import bring_value, get_value, get_bool_value, get_values
from farado.helpers.issue_report_helper import IssueReportHelper


class UsersView(BaseView):

    #--------------------------------------------------------------------------#
    def __init__(self):
        super().__init__()
        self.name = '/users'

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def index(self):
        user = self.current_user()
        if not user:
            return self.login_and_open()

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа к перечню пользователей."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        message = f"Открытие страницы с перечнем пользователей."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["users"].render(
            user=user,
            project_manager=project_manager(),
            operation_result=user.pop_last_action_result(),
            restriction=UiUserRestrictions(
                is_admin=is_admin,
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def user(self, target_user_id=None, **args):
        user = self.current_user()
        if not user:
            if target_user_id:
                return self.login_and_open(f'/user/{target_user_id}', args)
            return self.login_and_open()

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для изменения пользователя #{target_user_id}"
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        args = bring_value(user.pop_last_action_data(), args)
        target_user_login = get_value(args, 'target_user_login', None)
        target_user_email = get_value(args, 'target_user_email', None)
        target_user_first_name = get_value(args, 'target_user_first_name', None)
        target_user_middle_name = get_value(args, 'target_user_middle_name', None)
        target_user_last_name = get_value(args, 'target_user_last_name', None)
        target_user_password = get_value(args, 'target_user_password', None)
        target_user_need_change_password = get_bool_value(args, 'target_user_need_change_password', 'on', False)
        target_user_is_blocked = get_bool_value(args, 'target_user_is_blocked', 'on', False)

        target_user = project_manager().user_by_id(target_user_id)

        operation_result = user.pop_last_action_result()
        if target_user_login:
            if not target_user:
                target_user = User()

                message = f"Создание пользователя «{target_user_login}»."
                logger.info(f"%-18s | {message}", user.login)

            target_user.login = target_user_login
            target_user.email = target_user_email
            target_user.first_name = target_user_first_name
            target_user.middle_name = target_user_middle_name
            target_user.last_name = target_user_last_name
            target_user.need_change_password = target_user_need_change_password
            target_user.is_blocked = target_user_is_blocked
            if 0 < len(target_user_password):
                target_user.set_password(target_user_password)
            project_manager().save_item(target_user)
            operation_result = OperationResult(
                caption="Пользователь сохранён",
                kind="success"
            )

            # Присваивание нужно в том случае, если был создан новый пользователь.
            target_user_id = target_user.id

            message = f"Пользователь #{target_user_id} сохранён."
            logger.info(f"%-18s | {message}", user.login)

        message = f"Открытие страницы изменения параметров пользователя #{target_user_id}."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["user"].render(
            user=user,
            target_user=target_user,
            project_manager=project_manager(),
            operation_result=operation_result,
            restriction=UiUserRestrictions(
                is_admin=is_admin,
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def user_profile(self, target_user_id, **args):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/user_profile/{target_user_id}', args)

        is_admin = self.is_admin(user.id)
        if (not user.id == int(target_user_id)) and (not is_admin):
            message = f"Нет доступа для изменения другого пользователя #{target_user_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        args = bring_value(user.pop_last_action_data(), args)
        target_user_login = get_value(args, 'target_user_login', None)
        target_user_email = get_value(args, 'target_user_email', None)
        target_user_first_name = get_value(args, 'target_user_first_name', None)
        target_user_middle_name = get_value(args, 'target_user_middle_name', None)
        target_user_last_name = get_value(args, 'target_user_last_name', None)
        target_user_password = get_value(args, 'target_user_password', None)

        target_user = project_manager().user_by_id(target_user_id)
        if not target_user:
            message = f"Пользователь #{target_user_id} на найден."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        operation_result = user.pop_last_action_result()
        if target_user_login:
            target_user.login = target_user_login
            target_user.email = target_user_email
            target_user.first_name = target_user_first_name
            target_user.middle_name = target_user_middle_name
            target_user.last_name = target_user_last_name
            if 0 < len(target_user_password):
                target_user.set_password(target_user_password)
            project_manager().save_item(target_user)
            operation_result = OperationResult(
                caption="Пользователь сохранён",
                kind="success"
            )

            message = f"Пользователь #{target_user_id} сохранён."
            logger.info(f"%-18s | {message}", user.login)

        message = f"Открытие страницы профиля пользователя #{target_user_id}."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["user_profile"].render(
            user=user,
            target_user=target_user,
            project_manager=project_manager(),
            operation_result=operation_result,
            restriction=UiUserRestrictions(
                is_admin=is_admin,
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def user_statistics(self, user_id, **args):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/user_statistics/{user_id}', args)

        args = bring_value(user.pop_last_action_data(), args)
        target_user = project_manager().user_by_id(user_id)

        message = f"Открытие страницы статистики пользователя #{user_id}."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["user_statistics"].render(
            user=user,
            target_user=target_user,
            project_manager=project_manager(),
            statistics_helper=UserStatisticsHelper(target_user),
            restriction=UiUserRestrictions(
                is_admin=self.is_admin(user.id),
            )
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def add_user(self):
        user = self.current_user()
        if not user:
            return self.login_and_open('/add_user')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для создания пользователя."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        message = f"Открытие страницы создания пользователя."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["user"].render(
            user=user,
            project_manager=project_manager(),
            target_user=None,
            save_result=None,
            restriction=UiUserRestrictions(
                is_admin=is_admin,
                )
            )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def remove_user(self, target_user_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/remove_user/{target_user_id}', args)

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для удаления пользователя #{target_user_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        project_manager().remove_item(User, target_user_id)

        message = f"Пользователь #{target_user_id} удалён."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Пользователь удалён",
                kind="success"
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def add_user_role(self, target_user_id, target_role_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/add_user_role/{target_user_id}/{target_role_id}')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для добавления пользователю #{target_user_id} роли #{target_role_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        if not project_manager().user_by_id(target_user_id):
            message = f"Пользователь #{target_user_id} не найден."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        user_role = UserRole()
        user_role.role_id = int(target_role_id)
        user_role.user_id = int(target_user_id)
        project_manager().save_item(user_role)

        message = f"Роль #{target_role_id} добавлена пользователю #{target_user_id}."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="Пользователю добавлена роль",
                kind="success",
                tab_name='roles'
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/user/{target_user_id}'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def remove_user_role(self, target_user_id, target_user_role_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/remove_user_role/{target_user_id}/{target_user_role_id}')

        is_admin = self.is_admin(user.id)
        if not is_admin:
            message = f"Нет доступа для удаления роли #{target_user_role_id} у пользователя #{target_user_id}."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        if not project_manager().user_by_id(target_user_id):
            message = f"Пользователь #{target_user_id} не найден."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        project_manager().remove_item(UserRole, target_user_role_id)

        message = f"Роль удалена у пользователя #{target_user_id}."
        logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(
            OperationResult(
                caption="У пользователя удалена роль",
                kind="success",
                tab_name='roles',
            )
        )
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/user/{target_user_id}'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def messages(self, user_id=None, **args):
        user = self.current_user()
        if not user:
            if user_id:
                return self.login_and_open(f'/messages/{user_id}', args)
            return self.login_and_open(f'/messages', args)

        args = bring_value(user.pop_last_action_data(), args)
        operation_result = user.pop_last_action_result()

        if not user_id:
            user_id = user.id

        is_admin = self.is_admin(user.id)
        if not(is_admin or int(user_id) == user.id):
            message = f"Нет доступа для просмотра чужих сообщений."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        target_user = project_manager().user_by_id(user_id)

        message = f"Открытие страницы сообщений пользователя #{user_id}."
        logger.info(f"%-18s | {message}", user.login)

        return view_renderer["user_messages"].render(
            user=user,
            target_user=target_user,
            project_manager=project_manager(),
            restriction=UiUserRestrictions(
                is_admin=self.is_admin(user.id),
            ),
            operation_result=operation_result,
        )

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def send_message(self, user_id, **args):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/send_message/{user_id}', args)

        args = bring_value(user.pop_last_action_data(), args)

        is_admin = self.is_admin(user.id)
        if not(is_admin or int(user_id) == user.id):
            message = f"Нет доступа для отправки сообщений от чужого имени."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(403, message)

        operation_result = None
        message_caption = get_value(args, 'message_caption', None)
        message_content = get_value(args, 'message_content', None)
        message_receivers = get_values(args, 'message_receivers')
        for receiver_id in message_receivers:
            if receiver := project_manager().user(receiver_id):
                project_manager().save_item(
                    Message(
                        caption=message_caption,
                        content=message_content,
                        receiver_id=receiver_id,
                        sender_id=user_id,
                    )
                )
                if not operation_result: 
                    operation_result = OperationResult(
                        caption="Сообщение отправлено",
                        kind="success"
                    )

                    message = f"Отправлено сообщение."
                    logger.info(f"%-18s | {message}", user.login)

        user.push_last_action_result(operation_result)
        raise cherrypy.HTTPRedirect(cherrypy.url(f'/messages/{user_id}'))

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def read_message(self, user_id, message_id):
        user = self.current_user()
        if not user:
            return self.login_and_open(f'/read_message/{user_id}/{message_id}')

        is_admin = self.is_admin(user.id)
        if not(is_admin or int(user_id) == user.id):
            return

        message = project_manager().message(message_id)
        if not message.was_read:
            message.was_read = True
            project_manager().save_item(message)
            return 'was_read'
        return ''

    #--------------------------------------------------------------------------#
    @cherrypy.expose
    def report(self, user_id, **args):
        user = self.current_user()
        if not user:
            if user_id:
                return self.login_and_open(f'/report/{user_id}', args)
            return self.login_and_open()

        args = bring_value(user.pop_last_action_data(), args)

        from_date = f'{datetime.datetime.now():%d.%m.%Y}'
        to_date = from_date
        if date_range := get_value(args, 'daterange', None):
            date_range_container = date_range.split(" — ")
            from_date = date_range_container[0]
            to_date = date_range_container[1]

        target_user = project_manager().user_by_id(user_id)
        if not target_user:
            message = f"Пользователь #{user_id} не найден."
            logger.warn(f"%-18s | {message}", user.login)
            raise cherrypy.HTTPError(404, message)

        message = f"Формирование отчёта по пользователю #{user_id} "
        message += f"за период {from_date} — {to_date}."
        logger.info(f"%-18s | {message}", user.login)

        issues_periods = IssueReportHelper().active_issues_ids_in_period_by_user(
            from_date=from_date,
            to_date=to_date,
            user_id=user_id,
        )

        return view_renderer["user_statistics"].render(
            user=user,
            target_user=target_user,
            project_manager=project_manager(),
            operation_result=OperationResult(
                caption='Отчёт сформирован',
                result_code='secondary',
                tab_name='report'
            ),
            statistics_helper=UserStatisticsHelper(target_user),
            restriction=UiUserRestrictions(
                is_admin=self.is_admin(user.id),
            ),
            report_data=issues_periods,
            from_date=from_date,
            to_date=to_date,
        )
